home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / gui / x / xfig.lha / src / x11 / u_draw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-26  |  33.4 KB  |  1,232 lines

  1. /*
  2.  * FIG : Facility for Interactive Generation of figures
  3.  * Copyright (c) 1985 by Supoj Sutanthavibul
  4.  * Copyright (c) 1990 by Brian V. Smith
  5.  * Copyright (c) 1992 by James Tough
  6.  *
  7.  * "Permission to use, copy, modify, distribute, and sell this software and its
  8.  * documentation for any purpose is hereby granted without fee, provided that
  9.  * the above copyright notice appear in all copies and that both the copyright
  10.  * notice and this permission notice appear in supporting documentation. 
  11.  * No representations are made about the suitability of this software for 
  12.  * any purpose.  It is provided "as is" without express or implied warranty."
  13.  */
  14.  
  15. #include "fig.h"
  16. #include "resources.h"
  17. #include "object.h"
  18. #include "paintop.h"
  19. #include "u_bound.h"
  20. #include "u_create.h"
  21. #include "u_draw.h"
  22. #include "w_canvas.h"
  23. #include "w_drawprim.h"
  24. #include "w_zoom.h"
  25.  
  26. typedef unsigned char byte;
  27. extern PIX_ROT_FONT lookfont();
  28.  
  29. /************** POLYGON/CURVE DRAWING FACILITIES ****************/
  30.  
  31. static int    npoints;
  32. static int    max_points;
  33. static XPoint  *points;
  34. static int    allocstep;
  35.  
  36. static        Boolean
  37. init_point_array(init_size, step_size)
  38.     int            init_size, step_size;
  39. {
  40.     npoints = 0;
  41.     max_points = init_size;
  42.     allocstep = step_size;
  43.     if (max_points > MAXNUMPTS) {
  44.     put_msg("Too many points, recompile with MAXNUMPTS > %d in w_drawprim.h",
  45.         MAXNUMPTS);
  46.     max_points = MAXNUMPTS;
  47.     }
  48.     if ((points = (XPoint *) malloc(max_points * sizeof(XPoint))) == 0) {
  49.     fprintf(stderr, "xfig: insufficient memory to allocate point array\n");
  50.     return False;
  51.     }
  52.     return True;
  53. }
  54.  
  55. static        Boolean
  56. add_point(x, y)
  57.     int            x, y;
  58. {
  59.     if (npoints >= max_points) {
  60.     XPoint           *tmp_p;
  61.  
  62.     max_points += allocstep;
  63.     if (max_points >= MAXNUMPTS)
  64.         return False;    /* stop; it is not closing */
  65.  
  66.     if ((tmp_p = (XPoint *) realloc(points,
  67.                     max_points * sizeof(XPoint))) == 0) {
  68.         fprintf(stderr,
  69.             "xfig: insufficient memory to reallocate point array\n");
  70.         return False;
  71.     }
  72.     points = tmp_p;
  73.     }
  74.     points[npoints].x = (short) x;
  75.     points[npoints].y = (short) y;
  76.     npoints++;
  77.     return True;
  78. }
  79.  
  80. static void
  81. draw_point_array(w, op, line_width, line_style, style_val, fill_style, color)
  82.     Window        w;
  83.     int            op;
  84.     int            line_width, line_style;
  85.     float        style_val;
  86.     int            fill_style;
  87.     Color        color;
  88. {
  89.     pw_lines(w, points, npoints, op,
  90.          line_width, line_style, style_val, fill_style, color);
  91.     free(points);
  92. }
  93.  
  94. /*********************** ARC ***************************/
  95.  
  96. draw_arc(a, op)
  97.     F_arc       *a;
  98.     int            op;
  99. {
  100.     int            radius, rx, ry;
  101.     int            xmin, ymin, xmax, ymax;
  102.  
  103.     arc_bound(a, &xmin, &ymin, &xmax, &ymax);
  104.     if (!overlapping(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax),
  105.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  106.     return;
  107.  
  108.     rx = a->point[0].x - a->center.x;
  109.     ry = a->center.y - a->point[0].y;
  110.     radius = round(sqrt((double) (rx * rx + ry * ry)));
  111.  
  112.     curve(canvas_win, round(a->point[0].x - a->center.x),
  113.       round(a->center.y - a->point[0].y),
  114.       round(a->point[2].x - a->center.x),
  115.       round(a->center.y - a->point[2].y),
  116.       a->direction, 7*radius, radius, radius,
  117.       round(a->center.x), round(a->center.y), op,
  118.       a->thickness, a->style, a->style_val, a->fill_style, a->color);
  119.  
  120.     draw_arcarrows(a, op);
  121. }
  122.  
  123. /*********************** ELLIPSE ***************************/
  124.  
  125. draw_ellipse(e, op)
  126.     F_ellipse       *e;
  127.     int            op;
  128. {
  129.     int            a, b, xmin, ymin, xmax, ymax;
  130.  
  131.     ellipse_bound(e, &xmin, &ymin, &xmax, &ymax);
  132.     if (!overlapping(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax),
  133.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  134.     return;
  135.  
  136.     if (e->angle != 0.0) {
  137.     angle_ellipse(e->center.x, e->center.y, e->radiuses.x, e->radiuses.y, 
  138.         e->angle, op, e->thickness, e->style, 
  139.         e->style_val, e->fill_style, e->color);
  140.     /* it is much faster to use curve() for dashed and dotted lines that to
  141.        use the server's sloooow algorithms for that */
  142.     } else if (op != ERASE && (e->style == DOTTED_LINE || e->style == DASH_LINE)) {
  143.     a = e->radiuses.x;
  144.     b = e->radiuses.y;
  145.     curve(canvas_win, a, 0, a, 0, e->direction, 7*max2(a,b), (b * b), (a * a),
  146.           e->center.x, e->center.y, op,
  147.           e->thickness, e->style, e->style_val, e->fill_style, e->color);
  148.     /* however, for solid lines the server is muuuch faster even for thick lines */
  149.     } else {
  150.     xmin = e->center.x - e->radiuses.x;
  151.     ymin = e->center.y - e->radiuses.y;
  152.     xmax = e->center.x + e->radiuses.x;
  153.     ymax = e->center.y + e->radiuses.y;
  154.     pw_curve(canvas_win, xmin, ymin, xmax, ymax, op,
  155.          e->thickness, e->style, e->style_val, e->fill_style,
  156.          e->color);
  157.     }
  158. }
  159.  
  160. /*
  161.  *  An Ellipse Generator.
  162.  *  Written by James Tough   7th May 92
  163.  *
  164.  *  The following routines displays a filled ellipse on the screen from the
  165.  *    semi-minor axis 'a', semi-major axis 'b' and angle of rotation
  166.  *    'phi'.
  167.  *
  168.  *  It works along these principles .....
  169.  *
  170.  *        The standard ellipse equation is
  171.  *
  172.  *             x*x     y*y
  173.  *             ---  +  ---
  174.  *             a*a     b*b
  175.  *
  176.  *
  177.  *        Rotation of a point (x,y) is well known through the use of
  178.  *
  179.  *            x' = x*COS(phi) - y*SIN(phi)
  180.  *            y' = y*COS(phi) + y*COS(phi)
  181.  *
  182.  *        Taking these to together, this gives the equation for a rotated
  183.  *      ellipse centered around the origin.
  184.  *
  185.  *           [x*COS(phi) - y*SIN(phi)]^2   [x*SIN(phi) + y*COS(phi)]^2
  186.  *           --------------------------- + ---------------------------
  187.  *                      a*a                           b*b
  188.  *
  189.  *        NOTE -  some of the above equation can be precomputed, eg,
  190.  *
  191.  *              i = COS(phi)/a        and        j = SIN(phi)/b
  192.  *       
  193.  *        NOTE -  y is constant for each line so,
  194.  *
  195.  *              m = -yk*SIN(phi)/a    and     n = yk*COS(phi)/b
  196.  *              where yk stands for the kth line ( y subscript k)
  197.  *
  198.  *        Where yk=y, we get a quadratic,
  199.  *
  200.  *              (i*x + m)^2 + (j*x + n)^2 = 1
  201.  *
  202.  *        Thus for any particular line, y, there is two corresponding x
  203.  *      values. These are the roots of the quadratic. To get the roots, 
  204.  *      the above equation can be rearranged using the standard method, 
  205.  *
  206.  *          -(i*m + j*n) +- sqrt[i^2 + j^2 - (i*n -j*m)^2]
  207.  *      x = ----------------------------------------------
  208.  *                           i^2 + j^2 
  209.  *
  210.  *        NOTE -  again much of this equation can be precomputed.
  211.  *     
  212.  *           c1 = i^2 + j^2 
  213.  *           c2 = [COS(phi)*SIN(phi)*(a-b)]
  214.  *           c3 = [b*b*(COS(phi)^2) + a*a*(SIN(phi)^2)]
  215.  *           c4 = a*b/c3
  216.  * 
  217.  *      x = c2*y +- c4*sqrt(c3 - y*y),    where +- must be evaluated once
  218.  *                                      for plus, and once for minus. 
  219.  *
  220.  *        We also need to know how large the ellipse is. This condition
  221.  *      arises when the sqrt of the above equation evaluates to zero.
  222.  *      Thus the height of the ellipse is give by 
  223.  * 
  224.  *              sqrt[ b*b*(COS(phi)^2) + a*a*(SIN(phi)^2) ]
  225.  *
  226.  *       which just happens to be equal to sqrt(c3).
  227.  *
  228.  *         It is now possible to create a routine that will scan convert 
  229.  *       the ellipse on the screen.
  230.  *
  231.  *        NOTE -  c2 is the gradient of the new ellipse axis.
  232.  *                c4 is the new semi-minor axis, 'a'.
  233.  *           sqr(c3) is the new semi-major axis, 'b'.
  234.  *
  235.  *         These values could be used in a 4WS or 8WS ellipse generator
  236.  *       that does not work on rotation, to give the feel of a rotated
  237.  *       ellipse. These ellipses are not very accurate and give visable
  238.  *       bumps along the edge of the ellipse. However, these routines
  239.  *       are very quick, and give a good approximation to a rotated ellipse.
  240.  *
  241.  *       NOTES on the code given.
  242.  * 
  243.  *           All the routines take there parameters as ( x, y, a, b, phi ),
  244.  *           where x,y are the center of the ellipse ( relative to the 
  245.  *           origin ), a and b are the vertical and horizontal axis, and
  246.  *           phi is the angle of rotation in RADIANS.
  247.  *
  248.  *           The 'moveto(x,y)' command moves the screen cursor to the 
  249.  *               (x,y) point.
  250.  *           The 'lineto(x,y)' command draws a line from the cursor to
  251.  *               the point (x,y).
  252.  *
  253.  *
  254.  *   Examples,
  255.  *
  256.  *       NOTE, all angles must be given in radians.
  257.  *
  258.  *       angle_ellipse(0,0,100,20,PI/4)         an ellipse at the origin,
  259.  *                                             major axis 100, minor 20
  260.  *                                             at angle 45 degrees.
  261.  *
  262.  *
  263.  */
  264.  
  265.  
  266. /*
  267.  *  QuickEllipse, uses the same method as Ellipse, but uses incremental
  268.  *    methods to reduce the amount of work that has to be done inside
  269.  *    the main loop. The speed increase is very noticeable.
  270.  *
  271.  *  Written by James Tough
  272.  *  7th May 1992
  273.  * 
  274.  */
  275.  
  276. static int    x[MAXNUMPTS/4][4],y[MAXNUMPTS/4][4];
  277. static int    nump[4];
  278. static int    totpts,i,j;
  279. static int    order[4]={0,1,3,2};
  280.  
  281. angle_ellipse(center_x, center_y, radius_x, radius_y, angle,
  282.           op, thickness, style, style_val, fill_style, color)
  283.     int            center_x, center_y;
  284.     int            radius_x, radius_y;
  285.     float        angle;
  286.     int            op,thickness,style,fill_style,color;
  287.     float        style_val;
  288. {
  289.     float    xcen, ycen, a, b; 
  290.  
  291.     double    c1, c2, c3, c4, c5, c6, v1, cphi, sphi, cphisqr, sphisqr;
  292.     double    xleft, xright, d, asqr, bsqr;
  293.     int    ymax, yy=0;
  294.     int    k,m,dir;
  295.     float    savezoom, savexoff, saveyoff;
  296.     int    zoomthick;
  297.     XPoint    *ipnts;
  298.  
  299.     /* clear any previous error message */
  300.     put_msg("");
  301.     if (radius_x == 0 || radius_y == 0)
  302.         return;
  303.  
  304.     /* adjust for zoomscale so we iterate over zoomed pixels */
  305.     xcen = ZOOMX(center_x);
  306.     ycen = ZOOMY(center_y);
  307.     a = radius_x*zoomscale;
  308.     b = radius_y*zoomscale;
  309.     zoomthick = round(zoomscale*thickness);
  310.     if (zoomthick == 0 && thickness != 0)
  311.         zoomthick=1;
  312.     savezoom = zoomscale;
  313.     savexoff = zoomxoff;
  314.     saveyoff = zoomyoff;
  315.     zoomscale = 1.0;
  316.     zoomxoff = zoomyoff = 0.0;
  317.  
  318.     cphi = cos((double)angle);
  319.     sphi = sin((double)angle);
  320.     cphisqr = cphi*cphi;
  321.     sphisqr = sphi*sphi;
  322.     asqr = a*a;
  323.     bsqr = b*b;
  324.     
  325.     c1 = (cphisqr/asqr)+(sphisqr/bsqr);
  326.     c2 = ((cphi*sphi/asqr)-(cphi*sphi/bsqr))/c1;
  327.     c3 = (bsqr*cphisqr) + (asqr*sphisqr);
  328.     ymax = sqrt(c3);
  329.     c4 = a*b/c3;
  330.     c5 = 0;
  331.     v1 = c4*c4;
  332.     c6 = 2*v1;
  333.     c3 = c3*v1-v1;
  334.     totpts = 0;
  335.     for (i=0; i<=3; i++)
  336.         nump[i]=0;
  337.     i=0; j=0;
  338.     /* odd first points */
  339.     if (ymax % 2) {
  340.         d = sqrt(c3);
  341.         newpoint(xcen-d,ycen);
  342.         newpoint(xcen+d,ycen);
  343.         c5 = c2;
  344.         yy=1;
  345.     }
  346.     while (c3>=0) {
  347.         d = sqrt(c3);
  348.         xleft = c5-d;
  349.         xright = c5+d;                        
  350.         newpoint(xcen+xleft,ycen+yy);
  351.         newpoint(xcen+xright,ycen+yy);
  352.         newpoint(xcen-xright,ycen-yy);
  353.         newpoint(xcen-xleft,ycen-yy);
  354.         c5+=c2;
  355.         v1+=c6;
  356.         c3-=v1;
  357.         yy=yy+1;
  358.     }
  359.     dir=0;
  360.     totpts++;    /* add another point to join with first */
  361.     init_point_array(totpts, 0);
  362.     ipnts = points;
  363.     /* now go down the 1st column, up the 2nd, down the 4th 
  364.        and up the 3rd to get the points in the correct order */
  365.     for (k=0; k<=3; k++) {
  366.         if (dir==0)
  367.         for (m=0; m<nump[k]; m++) {
  368.             add_point(x[m][order[k]],y[m][order[k]]);
  369.         }
  370.         else
  371.         for (m=nump[k]-1; m>=0; m--) {
  372.             add_point(x[m][order[k]],y[m][order[k]]);
  373.         }
  374.         dir = 1-dir;
  375.     } /* next k */
  376.     /* add another point to join with first */
  377.     add_point(ipnts->x,ipnts->y);
  378.     draw_point_array(canvas_win, op, zoomthick, style, style_val, 
  379.          fill_style, color);
  380.  
  381.     zoomscale = savezoom;
  382.     zoomxoff = savexoff;
  383.     zoomyoff = saveyoff;
  384.     return;
  385. }
  386.  
  387. /* store the points across (row-wise in) the matrix */
  388.  
  389. newpoint(xp,yp)
  390.     float       xp,yp;
  391. {
  392.     if (totpts >= MAXNUMPTS/4) {
  393.     if (totpts == MAXNUMPTS/4) {
  394.         put_msg("Too many points to fully display rotated ellipse. %d points max",
  395.         MAXNUMPTS);
  396.         totpts++;
  397.     }
  398.     return;
  399.     }
  400.     x[i][j]=round(xp);
  401.     y[i][j]=round(yp);
  402.     nump[j]++;
  403.     totpts++;
  404.     if (++j > 3) {
  405.     j=0; 
  406.     i++;
  407.     }
  408. }
  409.  
  410.  
  411. /*********************** LINE ***************************/
  412.  
  413. draw_line(line, op)
  414.     F_line       *line;
  415.     int            op;
  416. {
  417.     F_point       *point;
  418.     int            xx, yy, x, y;
  419.     int            xmin, ymin, xmax, ymax;
  420.     char       *string;
  421.     F_point       *p0, *p1, *p2;
  422.     pr_size        txt;
  423.  
  424.     line_bound(line, &xmin, &ymin, &xmax, &ymax);
  425.     if (!overlapping(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax),
  426.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  427.     return;
  428.  
  429.     /* is it an arcbox? */
  430.     if (line->type == T_ARC_BOX) {
  431.     draw_arcbox(line, op);
  432.     return;
  433.     }
  434.     /* is it an eps file? */
  435.     if (line->type == T_EPS_BOX) {
  436.     if (line->eps->bitmap != NULL) {
  437.         draw_eps_pixmap(line, op);
  438.         return;
  439.     } else {        /* label empty eps bounding box */
  440.         if (line->eps->file[0] == '\0')
  441.         string = EMPTY_EPS;
  442.         else {
  443.         string = rindex(line->eps->file, '/');
  444.         if (string == NULL)
  445.             string = line->eps->file;
  446.         else
  447.             string++;
  448.         }
  449.         p0 = line->points;
  450.         p1 = p0->next;
  451.         p2 = p1->next;
  452.         xmin = min3(p0->x, p1->x, p2->x);
  453.         ymin = min3(p0->y, p1->y, p2->y);
  454.         xmax = max3(p0->x, p1->x, p2->x);
  455.         ymax = max3(p0->y, p1->y, p2->y);
  456.         canvas_font = lookfont(0, 12, 0.0);    /* get a size 12 font */
  457.         txt = pf_textwidth(canvas_font, strlen(string), string);
  458.         x = (xmin + xmax) / 2 - txt.x / 2;
  459.         y = (ymin + ymax) / 2;
  460.         pw_text(canvas_win, x, y, op, canvas_font, string, DEFAULT_COLOR);
  461.         /* return; */
  462.     }
  463.     }
  464.     /* get first point and coordinates */
  465.     point = line->points;
  466.     x = point->x;
  467.     y = point->y;
  468.  
  469.     /* is it a single point? */
  470.     if (line->points->next == NULL) {
  471.     /* draw but don't fill */
  472.     pw_point(canvas_win, x, y, line->thickness, op, line->color);
  473.     return;
  474.     }
  475.     if (line->back_arrow)    /* backward arrow  */
  476.     draw_arrow(point->next->x, point->next->y, x, y,
  477.            line->back_arrow, op, line->color);
  478.  
  479.     /* accumulate the points in an array - start with 50 */
  480.     if (!init_point_array(50, 50))
  481.     return;
  482.  
  483.     for (point = line->points; point != NULL; point = point->next) {
  484.     xx = x;
  485.     yy = y;
  486.     x = point->x;
  487.     y = point->y;
  488.     add_point(x, y);
  489.     }
  490.  
  491.     draw_point_array(canvas_win, op, line->thickness, line->style,
  492.              line->style_val, line->fill_style, line->color);
  493.  
  494.     if (line->for_arrow)
  495.     draw_arrow(xx, yy, x, y, line->for_arrow, op, line->color);
  496. }
  497.  
  498. draw_arcbox(line, op)
  499.     F_line       *line;
  500.     int            op;
  501. {
  502.     F_point       *point;
  503.     int            xmin, xmax, ymin, ymax;
  504.  
  505.     point = line->points;
  506.     xmin = xmax = point->x;
  507.     ymin = ymax = point->y;
  508.     while (point->next) {    /* find lower left (upper-left on screen) */
  509.     /* and upper right (lower right on screen) */
  510.     point = point->next;
  511.     if (point->x < xmin)
  512.         xmin = point->x;
  513.     else if (point->x > xmax)
  514.         xmax = point->x;
  515.     if (point->y < ymin)
  516.         ymin = point->y;
  517.     else if (point->y > ymax)
  518.         ymax = point->y;
  519.     }
  520.     pw_arcbox(canvas_win, xmin, ymin, xmax, ymax, line->radius, op,
  521.         line->thickness, line->style, line->style_val, line->fill_style,
  522.           line->color);
  523. }
  524.  
  525. draw_eps_pixmap(box, op)
  526.     F_line       *box;
  527.     int            op;
  528. {
  529.     int            xmin, ymin;
  530.     int            xmax, ymax;
  531.     int            width, height, rotation;
  532.     F_pos        origin;
  533.     F_pos        opposite;
  534.  
  535.     origin.x = ZOOMX(box->points->x);
  536.     origin.y = ZOOMY(box->points->y);
  537.     opposite.x = ZOOMX(box->points->next->next->x);
  538.     opposite.y = ZOOMY(box->points->next->next->y);
  539.  
  540.     xmin = min2(origin.x, opposite.x);
  541.     ymin = min2(origin.y, opposite.y);
  542.     xmax = max2(origin.x, opposite.x);
  543.     ymax = max2(origin.y, opposite.y);
  544.     if (op == ERASE) {
  545.     clear_region(xmin, ymin, xmax, ymax);
  546.     return;
  547.     }
  548.     width = abs(origin.x - opposite.x);
  549.     height = abs(origin.y - opposite.y);
  550.     rotation = 0;
  551.     if (origin.x > opposite.x && origin.y > opposite.y)
  552.     rotation = 180;
  553.     if (origin.x > opposite.x && origin.y <= opposite.y)
  554.     rotation = 270;
  555.     if (origin.x <= opposite.x && origin.y > opposite.y)
  556.     rotation = 90;
  557.  
  558.     if (box->eps->pix_rotation != rotation ||
  559.     box->eps->pix_width != width ||
  560.     box->eps->pix_height != height ||
  561.     box->eps->pix_flipped != box->eps->flipped)
  562.     create_eps_pixmap(box, rotation, width, height, box->eps->flipped);
  563.  
  564.     XCopyArea(tool_d, box->eps->pixmap, canvas_win, gccache[op],
  565.           0, 0, xmax - xmin, ymax - ymin, xmin, ymin);
  566.     XFlush(tool_d);
  567. }
  568.  
  569. /*
  570.  * The input to this routine is the bitmap which is the "preview"
  571.  * section of an encapsulated postscript file. That input bitmap
  572.  * has an arbitrary number of rows and columns. This routine
  573.  * re-samples the input bitmap creating an output bitmap of dimensions
  574.  * width-by-height. This output bitmap is made into an X-windows pixmap
  575.  * for display purposes.
  576.  */
  577. create_eps_pixmap(box, rotation, width, height, flipped)
  578.     F_line       *box;
  579.     int            rotation, width, height, flipped;
  580. {
  581.     int            i;
  582.     int            j;
  583.     byte       *data;
  584.     byte       *tdata;
  585.     int            nbytes;
  586.     int            bbytes;
  587.     int            ibit;
  588.     int            jbit;
  589.     int            wbit;
  590.  
  591.     if (box->eps->pixmap != 0)
  592.     XFreePixmap(tool_d, box->eps->pixmap);
  593.  
  594.     nbytes = (width + 7) / 8;
  595.     bbytes = (box->eps->bit_size.x + 7) / 8;
  596.     data = (byte *) malloc(nbytes * height);
  597.     tdata = (byte *) malloc(nbytes);
  598.     bzero(data, nbytes * height);    /* clear memory */
  599.  
  600.     /* create a new bitmap at the specified size (requires interpolation) */
  601.     if ((!flipped && (rotation == 0 || rotation == 180)) ||
  602.     (flipped && !(rotation == 0 || rotation == 180))) {
  603.     for (j = 0; j < height; j++)
  604.         for (i = 0; i < width; i++) {
  605.         ibit = box->eps->bit_size.x * i / width;
  606.         jbit = box->eps->bit_size.y * j / height;
  607.         wbit = *(box->eps->bitmap + jbit * bbytes + ibit / 8);
  608.         if (wbit & (1 << (7 - (ibit & 7))))
  609.             *(data + j * nbytes + i / 8) += (1 << (i & 7));
  610.         }
  611.     } else {
  612.     for (j = 0; j < height; j++)
  613.         for (i = 0; i < width; i++) {
  614.         ibit = box->eps->bit_size.x * j / height;
  615.         jbit = box->eps->bit_size.y * i / width;
  616.         wbit = *(box->eps->bitmap + jbit * bbytes + ibit / 8);
  617.         if (wbit & (1 << (7 - (ibit & 7))))
  618.             *(data + (height - j) * nbytes + i / 8) += (1 << (i & 7));
  619.         }
  620.     }
  621.  
  622.     /* horizontal swap */
  623.     if (rotation == 180 || rotation == 270)
  624.     for (j = 0; j < height; j++) {
  625.         bzero(tdata, nbytes);
  626.         for (i = 0; i < width; i++)
  627.         if (*(data + j * nbytes + (width - i - 1) / 8) & (1 << ((width - i - 1) & 7)))
  628.             *(tdata + i / 8) += (1 << (i & 7));
  629.         bcopy(tdata, data + j * nbytes, nbytes);
  630.     }
  631.  
  632.     /* vertical swap */
  633.     if ((!flipped && (rotation == 180 || rotation == 270)) ||
  634.     (flipped && !(rotation == 180 || rotation == 270)))
  635.     for (j = 0; j < (height + 1) / 2; j++) {
  636.         bcopy(data + j * nbytes, tdata, nbytes);
  637.         bcopy(data + (height - j - 1) * nbytes, data + j * nbytes, nbytes);
  638.         bcopy(tdata, data + (height - j - 1) * nbytes, nbytes);
  639.     }
  640.  
  641.     box->eps->pixmap = XCreatePixmapFromBitmapData(tool_d, canvas_win,
  642.                            (char *) data, width, height,
  643.                    (box->color >= 0 && box->color < NUMCOLORS) ?
  644.                 appres.color[box->color] : x_fg_color.pixel,
  645.                            x_bg_color.pixel,
  646.                           DefaultDepthOfScreen(tool_s));
  647.     free(data);
  648.     free(tdata);
  649.  
  650.     box->eps->pix_rotation = rotation;
  651.     box->eps->pix_width = width;
  652.     box->eps->pix_height = height;
  653.     box->eps->pix_flipped = flipped;
  654. }
  655.  
  656. /*********************** SPLINE ***************************/
  657.  
  658. draw_spline(spline, op)
  659.     F_spline       *spline;
  660.     int            op;
  661. {
  662.     int            xmin, ymin, xmax, ymax;
  663.  
  664.     spline_bound(spline, &xmin, &ymin, &xmax, &ymax);
  665.     if (!overlapping(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax),
  666.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  667.     return;
  668.  
  669.     if (int_spline(spline))
  670.     draw_intspline(spline, op);
  671.     else if (spline->type == T_CLOSED_NORMAL)
  672.     draw_closed_spline(spline, op);
  673.     else if (spline->type == T_OPEN_NORMAL)
  674.     draw_open_spline(spline, op);
  675. }
  676.  
  677. draw_intspline(s, op)
  678.     F_spline       *s;
  679.     int            op;
  680. {
  681.     F_point       *p1, *p2;
  682.     F_control       *cp1, *cp2;
  683.  
  684.     p1 = s->points;
  685.     cp1 = s->controls;
  686.     cp2 = cp1->next;
  687.     if (s->back_arrow)
  688.     draw_arrow(round(cp2->lx), round(cp2->ly), p1->x, p1->y,
  689.            s->back_arrow, op, s->color);
  690.  
  691.     if (!init_point_array(300, 200))
  692.     return;
  693.  
  694.     for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
  695.      p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
  696.     bezier_spline((float) p1->x, (float) p1->y, cp1->rx, cp1->ry,
  697.               cp2->lx, cp2->ly, (float) p2->x, (float) p2->y, op,
  698.               s->thickness, s->style, s->style_val);
  699.     }
  700.  
  701.     add_point(p1->x, p1->y);
  702.  
  703.     draw_point_array(canvas_win, op, s->thickness, s->style,
  704.              s->style_val, s->fill_style, s->color);
  705.  
  706.     if (s->for_arrow)
  707.     draw_arrow(round(cp1->lx), round(cp1->ly), p1->x,
  708.            p1->y, s->for_arrow, op, s->color);
  709. }
  710.  
  711. draw_open_spline(spline, op)
  712.     F_spline       *spline;
  713.     int            op;
  714. {
  715.     F_point       *p;
  716.     float        cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  717.     float        x1, y1, x2, y2;
  718.  
  719.     if (!init_point_array(300, 200))
  720.     return;
  721.  
  722.     p = spline->points;
  723.     x1 = p->x;
  724.     y1 = p->y;
  725.     p = p->next;
  726.     x2 = p->x;
  727.     y2 = p->y;
  728.     cx1 = (x1 + x2) / 2;
  729.     cy1 = (y1 + y2) / 2;
  730.     cx2 = (cx1 + x2) / 2;
  731.     cy2 = (cy1 + y2) / 2;
  732.     if (spline->back_arrow)    /* backward arrow  */
  733.     draw_arrow((int) x2, (int) y2, (int) x1, (int) y1,
  734.            spline->back_arrow, op, spline->color);
  735.     add_point((int) x1, (int) y1);
  736.  
  737.     for (p = p->next; p != NULL; p = p->next) {
  738.     x1 = x2;
  739.     y1 = y2;
  740.     x2 = p->x;
  741.     y2 = p->y;
  742.     cx4 = (x1 + x2) / 2;
  743.     cy4 = (y1 + y2) / 2;
  744.     cx3 = (x1 + cx4) / 2;
  745.     cy3 = (y1 + cy4) / 2;
  746.     quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, op,
  747.              spline->thickness, spline->style, spline->style_val,
  748.              spline->color);
  749.     cx1 = cx4;
  750.     cy1 = cy4;
  751.     cx2 = (cx1 + x2) / 2;
  752.     cy2 = (cy1 + y2) / 2;
  753.     }
  754.  
  755.     add_point(round(cx1), round(cy1));
  756.     add_point((int) x2, (int) y2);
  757.  
  758.     draw_point_array(canvas_win, op, spline->thickness, spline->style,
  759.              spline->style_val, spline->fill_style, spline->color);
  760.  
  761.     if (spline->for_arrow)    /* forward arrow  */
  762.     draw_arrow((int) x1, (int) y1, (int) x2, (int) y2,
  763.            spline->for_arrow, op, spline->color);
  764. }
  765.  
  766. draw_closed_spline(spline, op)
  767.     F_spline       *spline;
  768.     int            op;
  769. {
  770.     F_point       *p;
  771.     float        cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  772.     float        x1, y1, x2, y2;
  773.  
  774.     if (!init_point_array(300, 200))
  775.     return;
  776.  
  777.     p = spline->points;
  778.     x1 = p->x;
  779.     y1 = p->y;
  780.     p = p->next;
  781.     x2 = p->x;
  782.     y2 = p->y;
  783.     cx1 = (x1 + x2) / 2;
  784.     cy1 = (y1 + y2) / 2;
  785.     cx2 = (x1 + 3 * x2) / 4;
  786.     cy2 = (y1 + 3 * y2) / 4;
  787.  
  788.     for (p = p->next; p != NULL; p = p->next) {
  789.     x1 = x2;
  790.     y1 = y2;
  791.     x2 = p->x;
  792.     y2 = p->y;
  793.     cx4 = (x1 + x2) / 2;
  794.     cy4 = (y1 + y2) / 2;
  795.     cx3 = (x1 + cx4) / 2;
  796.     cy3 = (y1 + cy4) / 2;
  797.     quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, op,
  798.              spline->thickness, spline->style, spline->style_val,
  799.              spline->color);
  800.     cx1 = cx4;
  801.     cy1 = cy4;
  802.     cx2 = (cx1 + x2) / 2;
  803.     cy2 = (cy1 + y2) / 2;
  804.     }
  805.     x1 = x2;
  806.     y1 = y2;
  807.     p = spline->points->next;
  808.     x2 = p->x;
  809.     y2 = p->y;
  810.     cx4 = (x1 + x2) / 2;
  811.     cy4 = (y1 + y2) / 2;
  812.     cx3 = (x1 + cx4) / 2;
  813.     cy3 = (y1 + cy4) / 2;
  814.     quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, op,
  815.              spline->thickness, spline->style, spline->style_val,
  816.              spline->color);
  817.  
  818.     add_point((int) cx4, (int) cy4);
  819.  
  820.     draw_point_array(canvas_win, op, spline->thickness, spline->style,
  821.              spline->style_val, spline->fill_style, spline->color);
  822. }
  823.  
  824.  
  825. /*********************** TEXT ***************************/
  826.  
  827. static char    *hidden_text_string = "<<>>";
  828.  
  829. draw_text(text, op)
  830.     F_text       *text;
  831.     int            op;
  832. {
  833.     PR_SIZE        size;
  834.     int            x,y;
  835.     float        angle;
  836.     int            xmin, ymin, xmax, ymax;
  837.     int            x1,y1, x2,y2, x3,y3, x4,y4;
  838.  
  839.     if (appres.textoutline)    /* get corners of rectangle at actual angle */
  840.     text_bound_both(text, &xmin, &ymin, &xmax, &ymax, 
  841.               &x1,&y1, &x2,&y2, &x3,&y3, &x4,&y4);
  842.     else
  843.     text_bound(text, &xmin, &ymin, &xmax, &ymax);
  844.  
  845.     if (!overlapping(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax),
  846.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  847.     return;
  848.  
  849.     /* outline the text bounds in red if textoutline resource is set */
  850.     if (appres.textoutline && !hidden_text(text)) {
  851.     pw_vector(canvas_win, x1, y1, x2, y2, op, 1, RUBBER_LINE, 0.0, 4);
  852.     pw_vector(canvas_win, x2, y2, x3, y3, op, 1, RUBBER_LINE, 0.0, 4);
  853.     pw_vector(canvas_win, x3, y3, x4, y4, op, 1, RUBBER_LINE, 0.0, 4);
  854.     pw_vector(canvas_win, x4, y4, x1, y1, op, 1, RUBBER_LINE, 0.0, 4);
  855.     }
  856.  
  857.     x = text->base_x;
  858.     y = text->base_y;
  859.     angle = text->angle*180.0/M_PI;
  860.     if (text->type == T_CENTER_JUSTIFIED || text->type == T_RIGHT_JUSTIFIED) {
  861.     size = pf_textwidth(text->fontstruct, strlen(text->cstring), 
  862.                 text->cstring);
  863.     size.x = size.x/zoomscale;
  864.     if (text->type == T_CENTER_JUSTIFIED) {
  865.         if (angle < 90.0 - 0.001)
  866.         x -= size.x / 2;    /*   0 to  89 degrees */
  867.         else if (angle < 180.0 - 0.001)
  868.         y += size.x / 2;    /*  90 to 179 degrees */
  869.         else if (angle < 270.0 - 0.001)
  870.         x += size.x / 2;    /* 180 to 269 degrees */
  871.         else 
  872.         y -= size.x / 2;    /* 270 to 359 degrees */
  873.  
  874.     } else {    /* T_RIGHT_JUSTIFIED */
  875.         if (angle < 90.0 - 0.001)
  876.         x -= size.x;        /*   0 to  89 degrees */
  877.         else if (angle < 180.0 - 0.001)
  878.         y += size.x;        /*  90 to 179 degrees */
  879.         else if (angle < 270.0 - 0.001)
  880.         x += size.x;        /* 180 to 269 degrees */
  881.         else 
  882.         y -= size.x;        /* 270 to 359 degrees */
  883.     }
  884.     }
  885.     if (hidden_text(text))
  886.     pw_text(canvas_win, x, y, op, lookfont(0,12,text->angle),
  887.         hidden_text_string, DEFAULT_COLOR);
  888.     else
  889.     pw_text(canvas_win, x, y, op, text->fontstruct,
  890.         text->cstring, text->color);
  891. }
  892.  
  893. /*********************** COMPOUND ***************************/
  894.  
  895. void
  896. draw_compoundelements(c, op)
  897.     F_compound       *c;
  898.     int            op;
  899. {
  900.     F_line       *l;
  901.     F_spline       *s;
  902.     F_ellipse       *e;
  903.     F_text       *t;
  904.     F_arc       *a;
  905.     F_compound       *c1;
  906.  
  907.     if (!overlapping(ZOOMX(c->nwcorner.x), ZOOMY(c->nwcorner.y), 
  908.              ZOOMX(c->secorner.x), ZOOMY(c->secorner.y),
  909.              clip_xmin, clip_ymin, clip_xmax, clip_ymax))
  910.     return;
  911.  
  912.     for (l = c->lines; l != NULL; l = l->next) {
  913.     draw_line(l, op);
  914.     }
  915.     for (s = c->splines; s != NULL; s = s->next) {
  916.     draw_spline(s, op);
  917.     }
  918.     for (a = c->arcs; a != NULL; a = a->next) {
  919.     draw_arc(a, op);
  920.     }
  921.     for (e = c->ellipses; e != NULL; e = e->next) {
  922.     draw_ellipse(e, op);
  923.     }
  924.     for (t = c->texts; t != NULL; t = t->next) {
  925.     draw_text(t, op);
  926.     }
  927.     for (c1 = c->compounds; c1 != NULL; c1 = c1->next) {
  928.     draw_compoundelements(c1, op);
  929.     }
  930. }
  931.  
  932. /*************************** ARROWS ****************************
  933.  
  934.  draw arrow heading from (x1, y1) to (x2, y2)
  935.  
  936. ****************************************************************/
  937.  
  938. draw_arrow(x1, y1, x2, y2, arrow, op, color)
  939.     int            x1, y1, x2, y2, op;
  940.     F_arrow       *arrow;
  941.     Color        color;
  942. {
  943.     float        x, y, xb, yb, dx, dy, l, sina, cosa;
  944.     int            xc, yc, xd, yd;
  945.     float        wid = arrow->wid, ht = arrow->ht;
  946.  
  947.     dx = x2 - x1;
  948.     dy = y1 - y2;
  949.     l = sqrt((double) (dx * dx + dy * dy));
  950.     if (l == 0)
  951.     return;
  952.     sina = dy / l;
  953.     cosa = dx / l;
  954.     xb = x2 * cosa - y2 * sina;
  955.     yb = x2 * sina + y2 * cosa;
  956.     x = xb - ht;
  957.     y = yb - wid / 2;
  958.     xc = x * cosa + y * sina + .5;
  959.     yc = -x * sina + y * cosa + .5;
  960.     y = yb + wid / 2;
  961.     xd = x * cosa + y * sina + .5;
  962.     yd = -x * sina + y * cosa + .5;
  963.     pw_vector(canvas_win, xc, yc, x2, y2, op,
  964.           (int) arrow->thickness, arrow->style, 0.0, color);
  965.     pw_vector(canvas_win, xd, yd, x2, y2, op,
  966.           (int) arrow->thickness, arrow->style, 0.0, color);
  967. }
  968.  
  969. draw_arcarrows(a, op)
  970.     F_arc       *a;
  971.     int            op;
  972. {
  973.     int            x, y;
  974.  
  975.     if (a->for_arrow) {
  976.     compute_normal(a->center.x, a->center.y, a->point[2].x,
  977.                a->point[2].y, a->direction, &x, &y);
  978.     draw_arrow(x, y, a->point[2].x, a->point[2].y, a->for_arrow, op,
  979.            a->color);
  980.     }
  981.     if (a->back_arrow) {
  982.     compute_normal(a->center.x, a->center.y, a->point[0].x,
  983.                a->point[0].y, a->direction ^ 1, &x, &y);
  984.     draw_arrow(x, y, a->point[0].x, a->point[0].y,
  985.            a->back_arrow, op, a->color);
  986.     }
  987. }
  988.  
  989. /********************* CURVES FOR ARCS AND ELLIPSES ***************
  990.  
  991.  This routine plot two dimensional curve defined by a second degree
  992.  polynomial of the form : 2    2 f(x, y) = ax + by + g = 0
  993.  
  994.  (x0,y0) is the starting point as well as ending point of the curve. The curve
  995.  will translate with the offset xoff and yoff.
  996.  
  997.  This algorithm is derived from the eight point algorithm in : "An Improved
  998.  Algorithm for the generation of Nonparametric Curves" by Bernard W.
  999.  Jordan, William J. Lennon and Barry D. Holm, IEEE Transaction on Computers
  1000.  Vol C-22, No. 12 December 1973.
  1001.  
  1002.  Will fill the curve if fill_style is != 0
  1003.  
  1004. ****************************************************************/
  1005.  
  1006. curve(window, xstart, ystart, xend, yend, direction, estnpts,
  1007.       a, b, xoff, yoff, op, thick, style, style_val, fill_style, color)
  1008.     Window        window;
  1009.     int            xstart, ystart, xend, yend, a, b, xoff, yoff;
  1010.     int            direction, estnpts, op, thick, style, fill_style;
  1011.     float        style_val;
  1012.     int            color;
  1013. {
  1014.     register int    deltax, deltay, dfx, dfy, x, y;
  1015.     int            dfxx, dfyy;
  1016.     int            falpha, fx, fy, fxy, absfx, absfy, absfxy;
  1017.     int            margin, test_succeed, inc, dec;
  1018.  
  1019.     if (a == 0 || b == 0)
  1020.     return;
  1021.  
  1022.     if (!init_point_array(estnpts,estnpts/2)) /* estimate of number of points */
  1023.     return;
  1024.  
  1025.     x = xstart;
  1026.     y = ystart;
  1027.     dfx = 2 * a * xstart;
  1028.     dfy = 2 * b * ystart;
  1029.     dfxx = 2 * a;
  1030.     dfyy = 2 * b;
  1031.  
  1032.     falpha = 0;
  1033.     if (direction) {
  1034.     inc = 1;
  1035.     dec = -1;
  1036.     } else {
  1037.     inc = -1;
  1038.     dec = 1;
  1039.     }
  1040.     if (xstart == xend && ystart == yend) {
  1041.     test_succeed = margin = 1;
  1042.     } else {
  1043.     test_succeed = margin = 1;
  1044.     }
  1045.  
  1046.     if (!add_point(xoff + x, yoff - y))
  1047.     /* (error) */ ;
  1048.     else
  1049.       while (test_succeed) {
  1050.     deltax = (dfy < 0) ? inc : dec;
  1051.     deltay = (dfx < 0) ? dec : inc;
  1052.     fx = falpha + dfx * deltax + a;
  1053.     fy = falpha + dfy * deltay + b;
  1054.     fxy = fx + fy - falpha;
  1055.     absfx = abs(fx);
  1056.     absfy = abs(fy);
  1057.     absfxy = abs(fxy);
  1058.  
  1059.     if ((absfxy <= absfx) && (absfxy <= absfy))
  1060.         falpha = fxy;
  1061.     else if (absfy <= absfx) {
  1062.         deltax = 0;
  1063.         falpha = fy;
  1064.     } else {
  1065.         deltay = 0;
  1066.         falpha = fx;
  1067.     }
  1068.     x += deltax;
  1069.     y += deltay;
  1070.     dfx += (dfxx * deltax);
  1071.     dfy += (dfyy * deltay);
  1072.     if (!add_point(xoff + x, yoff - y))
  1073.         break;
  1074.  
  1075.     if (abs(x - xend) < margin && abs(y - yend) < margin)
  1076.         test_succeed--;
  1077.     }
  1078.  
  1079.     if (xstart == xend && ystart == yend)    /* end points should touch */
  1080.     add_point(xoff + xstart, yoff - ystart);
  1081.  
  1082.     draw_point_array(window, op, thick, style, style_val, fill_style, color);
  1083. }
  1084.  
  1085. /********************* CURVES FOR SPLINES *****************************
  1086.  
  1087.     The following spline drawing routine is from
  1088.  
  1089.     "An Algorithm for High-Speed Curve Generation"
  1090.     by George Merrill Chaikin,
  1091.     Computer Graphics and Image Processing, 3, Academic Press,
  1092.     1974, 346-349.
  1093.  
  1094.     and
  1095.  
  1096.     "On Chaikin's Algorithm" by R. F. Riesenfeld,
  1097.     Computer Graphics and Image Processing, 4, Academic Press,
  1098.     1975, 304-310.
  1099.  
  1100. ***********************************************************************/
  1101.  
  1102. #define        half(z1, z2)    ((z1+z2)/2.0)
  1103. #define        THRESHOLD    5
  1104.  
  1105. /* iterative version */
  1106. /*
  1107.  * because we draw the spline with small line segments, the style parameter
  1108.  * doesn't work
  1109.  */
  1110.  
  1111. quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4, op, thick, style,
  1112.          style_val, color)
  1113.     float        a1, b1, a2, b2, a3, b3, a4, b4;
  1114.     int            op, thick, style;
  1115.     float        style_val;
  1116.     int            color;
  1117. {
  1118.     register float  xmid, ymid;
  1119.     float        x1, y1, x2, y2, x3, y3, x4, y4;
  1120.  
  1121.     clear_stack();
  1122.     push(a1, b1, a2, b2, a3, b3, a4, b4);
  1123.  
  1124.     while (pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
  1125.     xmid = half(x2, x3);
  1126.     ymid = half(y2, y3);
  1127.     if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
  1128.         fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
  1129.         add_point(round(x1), round(y1));
  1130.         add_point(round(xmid), round(ymid));
  1131.     } else {
  1132.         push(xmid, ymid, half(xmid, x3), half(ymid, y3),
  1133.          half(x3, x4), half(y3, y4), x4, y4);
  1134.         push(x1, y1, half(x1, x2), half(y1, y2),
  1135.          half(x2, xmid), half(y2, ymid), xmid, ymid);
  1136.     }
  1137.     }
  1138. }
  1139.  
  1140. /*
  1141.  * the style parameter doesn't work for splines because we use small line
  1142.  * segments
  1143.  */
  1144.  
  1145. bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3, op, thick, style, style_val)
  1146.     float        a0, b0, a1, b1, a2, b2, a3, b3;
  1147.     int            op, thick, style;
  1148.     float        style_val;
  1149. {
  1150.     register float  tx, ty;
  1151.     float        x0, y0, x1, y1, x2, y2, x3, y3;
  1152.     float        sx1, sy1, sx2, sy2, tx1, ty1, tx2, ty2, xmid, ymid;
  1153.  
  1154.     clear_stack();
  1155.     push(a0, b0, a1, b1, a2, b2, a3, b3);
  1156.  
  1157.     while (pop(&x0, &y0, &x1, &y1, &x2, &y2, &x3, &y3)) {
  1158.     if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD) {
  1159.         add_point(round(x0), round(y0));
  1160.     } else {
  1161.         tx = half(x1, x2);
  1162.         ty = half(y1, y2);
  1163.         sx1 = half(x0, x1);
  1164.         sy1 = half(y0, y1);
  1165.         sx2 = half(sx1, tx);
  1166.         sy2 = half(sy1, ty);
  1167.         tx2 = half(x2, x3);
  1168.         ty2 = half(y2, y3);
  1169.         tx1 = half(tx2, tx);
  1170.         ty1 = half(ty2, ty);
  1171.         xmid = half(sx2, tx1);
  1172.         ymid = half(sy2, ty1);
  1173.  
  1174.         push(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
  1175.         push(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
  1176.     }
  1177.     }
  1178. }
  1179.  
  1180. /* utilities used by spline drawing routines */
  1181.  
  1182. #define        STACK_DEPTH        20
  1183.  
  1184. typedef struct stack {
  1185.     float        x1, y1, x2, y2, x3, y3, x4, y4;
  1186. }
  1187.         Stack;
  1188.  
  1189. static Stack    stack[STACK_DEPTH];
  1190. static Stack   *stack_top;
  1191. static int    stack_count;
  1192.  
  1193. clear_stack()
  1194. {
  1195.     stack_top = stack;
  1196.     stack_count = 0;
  1197. }
  1198.  
  1199. push(x1, y1, x2, y2, x3, y3, x4, y4)
  1200.     float        x1, y1, x2, y2, x3, y3, x4, y4;
  1201. {
  1202.     stack_top->x1 = x1;
  1203.     stack_top->y1 = y1;
  1204.     stack_top->x2 = x2;
  1205.     stack_top->y2 = y2;
  1206.     stack_top->x3 = x3;
  1207.     stack_top->y3 = y3;
  1208.     stack_top->x4 = x4;
  1209.     stack_top->y4 = y4;
  1210.     stack_top++;
  1211.     stack_count++;
  1212. }
  1213.  
  1214. int
  1215. pop(x1, y1, x2, y2, x3, y3, x4, y4)
  1216.     float       *x1, *y1, *x2, *y2, *x3, *y3, *x4, *y4;
  1217. {
  1218.     if (stack_count == 0)
  1219.     return (0);
  1220.     stack_top--;
  1221.     stack_count--;
  1222.     *x1 = stack_top->x1;
  1223.     *y1 = stack_top->y1;
  1224.     *x2 = stack_top->x2;
  1225.     *y2 = stack_top->y2;
  1226.     *x3 = stack_top->x3;
  1227.     *y3 = stack_top->y3;
  1228.     *x4 = stack_top->x4;
  1229.     *y4 = stack_top->y4;
  1230.     return (1);
  1231. }
  1232.